# -*- coding: UTF-8 -*-
"""
子类重写父类同名方法

子类调用父类方法 super
# 子类调用父类的同名方法 一共有三种方法:
01 父类名.父类方法名(self)
# 02 super(子类名, self).父类方法名()
# 03 super().父类方法名()

# 02 和 03 只适用于新式类
# 02 和 03 一般用于单继承  也可以是多继承 但是只能调用第一个父类的方法
# 01 适用于单继承或者多继承都可以

私有方法，私有属性
# print(self.__money)
# self.__hello_python()
# Master().__hello_python()

类属性，类方法
每个类方法上面必须有@classmethod
# 格式:@classmethod
# def 方法名(cls)
# 02 类方法 调用
# 01格式: 类名.类方法名()
# print(Person.get_country())
# 02格式: 对象名.类方法名()
# p = Person()
# print(p.get_country())

# 格式:@staticmethod
# def 方法名():
# 03 静态方法 调用
# 01格式: 类名.静态方法名()
# Person.hello_python()
# 02格式: 对象名.静态方法名()
# p = Person()
# p.hello_python()


面向对象的三大特征:

1. 封装：属性和方法放到类内部，通过对象访问属性或者方法,


2. 继承：子类需要复用父类里面的属性或者方法,
		当然子类还可以提供自己的属性和方法;

3. 多态：同一个方法不同对象调用同一个方法功能的表现形式不一样，
例如:1.不同的两个对象，字符串的加法和整数的加法，
		同样是加法，实现的功能是不一样的；
	2.这两个对象之间没有任何直接继承关系，
		但是所有对象的最终父类都是元类；

"""
# class Master(object):
#     __country = "china"
#     country = "俄罗斯"
#
#     def __init__(self):
#         # 配方
#         self.kongfu = "古法配方"
#         # 钱
#         # 如果一个属性是以两个下划线开始 就标
#         self.__money = 10000
#
#
#     def make_cake(self, new_money):
#         print("古法煎饼果子")
#         # 私有属性和私有方法可以在类的里面使用
#         self.__money = new_money
#     def get_make_cake(self):
#         return self.__money
#
#     @classmethod
#     def set_country(cls, new_country):
#         cls.__country = new_country
#
#     @classmethod
#     def get_country(cls):
#         return cls.__country
#
#
#
#     # 如果一个方法是以两个下划线开始 也代表已经私
#     def __hello_python(self):
#         print("你好python")
#
# lishifu = Master()

# 测试
# lishifu.make_cake(1200)
# # lishifu.country ="北京"
# # print(lishifu.country)
# # del lishifu.country
# print(Master.country)
# # # lishifu.set_country("上海")
# # print(lishifu.get_country())
# Master.set_country("哈尔滨")
# print(Master.get_country())
#
# Master.country = "sdsdd"
# print(Master.country)


"""多态"""

# class Animal(object):
#
#     def __init__(self):
#         self.name = "ggrrr"
#         # print(self.name)
#
#     def run(self):
#         self.__init__()
#         print('Animal is running...',self.name)
#
#
#     def eat(self):
#         print("eat,,animal")
#         self.run()
#
#
# class Dog(Animal):
#
#     def run(self):
#         print('Dog is running...')
#
#     def eat(self):
#         super().__init__()
#         self.name ="qwww"
#         print('Eating meat...',self.name)
#         super().run()


# dog =Dog()
# dog.eat()

# class Cat(Animal):
#
#     def run(self):
#         print('Cat is running...')
#
# class Tortoise(Animal):
#     def run(self):
#         print('Tortoise is running slowly...')
# #
# def run_twice(animal):
#
#     animal.run()
#
# run_twice(Animal())
# run_twice(Cat())
# run_twice(Dog())
# run_twice(Tortoise())

# class Person(object):
#     instance = None
#     is_first = True
#
#     def __new__(cls, *args, **kwargs):
#         if not cls.instance:
#             cls.instance = object.__new__(cls)
#         return cls.instance
#
#     def __init__(self, name):
#         if Person.is_first:
#             print("init")
#             self.name = name
#             Person.is_first = False
#
# xiaoming = Person("小明")
# print(xiaoming)
# xiaohonh = Person("XIAOHONG")
# print(xiaohonh)

class Singleton(object):
    __instance = None
    __a = True
    # if not x == if x is None
    # 是最好的写法，清晰，不会出现错误，以后坚持使用这种写法。
    #
    # 使用if
    # not x这种写法的前提是：必须清楚x等于None, False, 空字符串
    # "", 0, 空列表[], 空字典
    # {}, 空元组()
    # 时对你的判断没有影响才行。
    def __new__(cls,*args,**kwargs):
        # 如果类属性__instance的值为None，
        # 那么就创建一个对象，并且赋值为这个对象的引用，保证下次调用这个方法时
        # 能够知道之前已经创建过对象了，这样就保证了只有1个对象
        if  cls.__instance is None:
            cls.__instance = object.__new__(cls)
        return cls.__instance

    def __init__(self,age,name):
        if Singleton.__a:
            self.name =name
            self.age = age
            Singleton.__a = False

    def __str__(self):
        return "年龄%s,姓名:%s" % (self.age,self.name)

    def __del__(self):
        print("del")




a = Singleton("17","wang")

print(id(a))
# a.age=188
print(a)

b = Singleton("18","li")
# b.age=177
print(id(b))

# a.age = 19 #给a指向的对象添加一个属性
# print(b.age)#获取b指向的对象的age属性

print(b)
